<template>
  <div class="message-private-chat">
    <!-- 上方应用菜单 -->
    <mu-appbar v-if="appbar" style="width: 100%" color="primary">
      <!-- 返回 -->
      <mu-menu slot="left">
        <mu-button flat @click="$router.go(-1)">
          <mu-icon value="arrow_back"></mu-icon>
        </mu-button>
      </mu-menu>

      <p style="text-align: center">{{ chatUser.realname }}</p>

      <!-- 菜单栏 -->
      <mu-menu slot="right">
        <mu-button flat text-color="#fff" @click="setOpen(!open)">
          <mu-icon value="menu"></mu-icon>
        </mu-button>
      </mu-menu>
    </mu-appbar>

    <!-- 消息 -->
    <match-parent>
      <pull-down ref="pullDown" :show-load-link="showLoadLink" :loading="loading" load-text="下拉加载更多" :has-more="hasMore" @load="loadMore()">
        <ul v-if="hasContent" class="chat-message-list">
          <message-private-item
            v-for="item in itemList"
            :key="item.id"
            :type="item.type"
            :item="item.item"
          />
        </ul>
        <ul v-else class="chat-message-list">
          <message-private-item
            type="error"
            :item="noContent"
          />
        </ul>
      </pull-down>
    </match-parent>

    <!-- 输入 -->
    <div class="input">
      <mu-text-field v-model="input" class="input-text-field" multi-line :rows="1" :rows-max="3" />
      <mu-button class="input-button" small color="primary" @click="send()">发送</mu-button>
    </div>
  </div>
</template>

<script>
import { mapGetters, mapMutations } from 'vuex'
import store from '@/store'
import Toast from 'muse-ui-toast'
import api from '@/api'
import MatchParent from '@/components/MatchParent'
import PullDown from '@/components/PullDown'
import MessagePrivateItem from './MessagePrivateItem'
import { buildItemList, TimedError } from './util'
import { readPrivateMessages } from '@/api/mixed-requests'

export default {
  name: 'MessagePrivateChat',
  components: {
    MessagePrivateItem,
    MatchParent,
    PullDown
  },
  props: {
    id: {
      type: Number,
      required: true
    },
    appbar: {
      type: Boolean,
      default: true
    },
    showLoadLink: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      total: 0,
      messageList: [],
      errorList: [],
      input: '',
      loading: false,
      lastRemain: 0,
      noContent: new Error('没有消息哦')
    }
  },
  computed: {
    ...mapGetters({
      open: 'phoneAsideDrawer',
      getUserById: 'getUserById',
      currentUserId: 'currentUserId'
    }),
    chatUser() {
      return this.getUserById(this.id)
    },
    oldestMessage() {
      return [...this.messageList].pop()
    },
    newestMessage() {
      return [...this.messageList].shift()
    },
    mergedList() {
      const list = [...this.messageList, ...this.errorList]
      list.sort((a, b) => {
        return b.create_at - a.create_at
      })
      return list
    },
    reversedMergedList() {
      return [...this.mergedList].reverse()
    },
    itemList() {
      return buildItemList(this.reversedMergedList)
    },
    hasMore() {
      return this.messageList.length < this.total
    },
    hasContent() {
      return this.mergedList.length > 0
    }
  },
  watch: {
    async messageList(val) {
      this.readMessages(val)
    },
    id() {
      this.initialize()
    }
  },
  mounted() {
    this.initialize()
  },
  methods: {
    ...mapMutations({
      setOpen: 'SET_PHONE_ASIDE_DRAWER',
      setPrivateMessageCount: 'SET_PRIVATE_MESSAGE_COUNT'
    }),
    // 初始化
    async initialize(length = 5) {
      this.loading = true
      try {
        this.messageList = []
        this.errorList = []
        const data = await api.fetchPrivateMessages(this.id, this.messageList.length, length)
        this.messageList = data.data
        this.total = data.total
      } catch (err) {
        this.errorList.push(new TimedError(err))
      }
      this.loading = false
    },
    // 加载更多（旧的）
    async loadMore(length = 10) {
      this.loading = true
      try {
        this.lastRemain = this.$refs.pullDown.getRemainHeight()
        const data = await api.fetchPrivateMessages(this.id, this.messageList.length, length)
        this.messageList = [...this.messageList, ...data.data]
        this.total = data.total
        this.$nextTick(() => {
          this.$refs.pullDown.setRemainHeight(this.lastRemain)
          this.lastRemain = 0
        })
      } catch (err) {
        this.errorList.push(new TimedError(err))
      }
      this.loading = false
    },
    // 加载最新（新的）
    async loadRecent(step = 5) {
      this.loading = true
      try {
        const last = this.newestMessage
        if (last) {
          const recentList = await this.getRecentList(step, last.id)
          this.messageList = [...recentList, ...this.messageList]
        }
      } catch (err) {
        this.errorList.push(new TimedError(err))
      }
      this.loading = false
    },
    // 获取最近列表，直到遇到stopID编号的消息位置，最多尝试maxTry次
    async getRecentList(step, stopId, maxTry = 5) {
      const recentList = []
      let offset = 0
      for (let i = 0; i < maxTry; i++) {
        const data = await api.fetchPrivateMessages(this.id, offset, step)
        this.total = data.total
        offset += step
        for (const item of data.data) {
          if (item.id === stopId) {
            return recentList
          } else {
            recentList.push(item)
          }
        }
      }
      throw new Error('未读消息太多，请刷新查看消息')
    },
    // 发送消息
    async send() {
      try {
        await api.createPrivateMessage(this.id, this.input)
        await this.loadRecent()
        this.$nextTick(() => {
          this.input = ''
          this.$refs.pullDown.setRemainHeight(0)
          this.lastRemain = 0
        })
      } catch (err) {
        this.errorList.push(new TimedError(err))
      }
    },
    // 标记已读某些消息
    async readMessages(messages) {
      try {
        const receivdMessages = messages.filter(it => it.to_id === this.currentUserId)
        const data = await readPrivateMessages(receivdMessages)
        const privateMessageCount = data.privateMessageCount
        if (privateMessageCount) {
          this.setPrivateMessageCount(privateMessageCount)
        }
        this.$emit('refresh')
        for (const k in data) {
          if (data[k] instanceof Error) {
            this.errorList.push(new TimedError(data[k]))
          }
        }
      } catch (err) {
        this.errorList.push(new TimedError(err))
      }
    }
  },
  beforeRouteEnter(to, from, next) {
    const currentUserId = store.getters.currentUserId
    const id = parseInt(to.params.id)
    if (id === currentUserId) {
      Toast.warning('你在尝试和自己聊天哦？')
    }
    next()
  }
}
</script>

<style scoped>
.message-private-chat {
  display: flex;
  flex-flow: column nowrap;
  height: 100%;
  background-color: #eaedf4;
}
.chat-message-list {
  list-style: none;
}
.input {
  position: relative;
  z-index: 10;
  padding: 3px;
  display: flex;
  flex-flow: row;
  align-items: center;
  box-shadow: 0 -1px 1px 0 rgba(60,60,60,.07), 0 -1px 3px 0 rgba(60,60,60,.06);
}
.input-text-field {
  flex: 1 1 auto;
  padding: 3px 0;
  margin: 0;
  min-height: 20px;
}
.input-button {
  margin-left: 3px;
}

.is-night .message-private-chat {
  background-color: #303030;
}
</style>
